﻿using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

// 菜单
public class Menu: MonoBehaviour {
    private Dictionary<GameObject, Action> mActions; // 所有菜单项的单击回调
    private List<GameObject> mMenuItems;             // 所有菜单项
    private GameObject mPanel;                       // 菜单项面板
    private GameObject mPrefabMenuItem;              // 预制菜单项
    private EventTrigger.Entry mPointClickEntry;     // 鼠标单击事件入口
    private EventTrigger.Entry mPointEnterEntry;     // 鼠标进入事件入口
    private EventTrigger.Entry mPointExitEntry;      // 鼠标离开事件入口
    private float mWidth = 0;                        // 自身宽度

    /**
     * 添加菜单项。
     * @param   菜单项标题
     * @param   菜单项的单击响应方法
     */
    public void Add(string title, Action action) {
        // 创建菜单项
        GameObject menuItem = Instantiate(mPrefabMenuItem);
        menuItem.SetActive(true);
        menuItem.transform.SetParent(mPanel.transform);

        // 添加鼠标事件回调
        EventTrigger eventTrigger = menuItem.GetComponent<EventTrigger>();
        eventTrigger.triggers.Add(mPointEnterEntry);
        eventTrigger.triggers.Add(mPointExitEntry);
        eventTrigger.triggers.Add(mPointClickEntry);
        mActions.Add(menuItem, action);

        // 设置文字
        Text text = menuItem.transform.GetComponentInChildren<Text>();
        text.text = title;

        // 设置菜单项的尺寸和位置
        if (mMenuItems.Count == 0) {
            // 设置菜单宽度，高度不变
            mWidth = text.fontSize * (text.text.Length + 1);
            RectTransform rectTransform = menuItem.GetComponent<RectTransform>();
            rectTransform.sizeDelta = new Vector2(mWidth, rectTransform.sizeDelta.y);

            // 设置菜单项位置
            RectTransform menuRectTransform = gameObject.GetComponent<RectTransform>();
            float x = (mWidth - menuRectTransform.sizeDelta.x) / 2;
            float y = -menuRectTransform.sizeDelta.y + 2;
            rectTransform.anchoredPosition = new Vector2(x, y);

            // 保存菜单项
            mMenuItems.Add(menuItem);
        } else {
            // 设置菜单项位置
            GameObject lastMenuItem = mMenuItems[mMenuItems.Count - 1];
            RectTransform lastRectTransform = lastMenuItem.GetComponent<RectTransform>();
            RectTransform newRectTransform = menuItem.GetComponent<RectTransform>();
            float y = lastRectTransform.anchoredPosition.y - newRectTransform.sizeDelta.y + 2;
            newRectTransform.anchoredPosition = new Vector2(lastRectTransform.anchoredPosition.x, y);

            // 保存菜单项
            mMenuItems.Add(menuItem);

            // 设置菜单宽度，高度不变
            float width = text.fontSize * (text.text.Length + 1);
            if (width <= mWidth) {
                // 新菜单项的宽度不大于菜单宽度，则将菜单宽度设置为新菜单项的宽度
                width = mWidth;
                newRectTransform.sizeDelta = new Vector2(width, newRectTransform.sizeDelta.y);
            } else {
                // 新菜单项的宽度大于菜单宽度，则将现在的所有菜单项的宽度设置为新菜单项的宽度
                mWidth = width;
                foreach (GameObject mi in mMenuItems) {
                    RectTransform rectTransform = mi.GetComponent<RectTransform>();
                    rectTransform.sizeDelta = new Vector2(mWidth, rectTransform.sizeDelta.y);
                    RectTransform menuRectTransform = gameObject.GetComponent<RectTransform>();
                    float x = (mWidth - menuRectTransform.sizeDelta.x) / 2;
                    rectTransform.anchoredPosition = new Vector2(x, rectTransform.anchoredPosition.y);
                }
            }
        }
    }

    /**
     * 唤醒。
     */
    private void Awake() {
        // 初始化成员
        mActions = new Dictionary<GameObject, Action>();
        mMenuItems = new List<GameObject>();
        mPanel = transform.GetChild(0).gameObject;
        mPointClickEntry = new EventTrigger.Entry();
        mPointEnterEntry = new EventTrigger.Entry();
        mPointExitEntry = new EventTrigger.Entry();
        mPrefabMenuItem = mPanel.transform.GetChild(0).gameObject;
        mWidth = 0;
        
         // 创建鼠标单击事件回调
        mPointClickEntry.eventID = EventTriggerType.PointerClick;
        mPointClickEntry.callback = new EventTrigger.TriggerEvent();
        mPointClickEntry.callback.AddListener(OnMouseClick);

        // 创建鼠标进入事件回调
        mPointEnterEntry.eventID = EventTriggerType.PointerEnter;
        mPointEnterEntry.callback = new EventTrigger.TriggerEvent();
        mPointEnterEntry.callback.AddListener(OnMouseEnter);

        // 创建鼠标离开事件回调
        mPointExitEntry.eventID = EventTriggerType.PointerExit;
        mPointExitEntry.callback = new EventTrigger.TriggerEvent();
        mPointExitEntry.callback.AddListener(OnMouseExit);

        // 添加鼠标事件回调
        EventTrigger eventTrigger = gameObject.GetComponent<EventTrigger>();
        eventTrigger.triggers.Add(mPointEnterEntry);
        eventTrigger.triggers.Add(mPointExitEntry);
    }

    /**
     * 隐藏自身。
     */
    private void Hide() {
        mPanel.SetActive(false);
    }

    /**
     * 鼠标单击事件的响应方法。
     * @param e 事件相关信息
     */
    private void OnMouseClick(BaseEventData e) {
        mActions[e.selectedObject].Invoke();
    }

    /**
     * 鼠标进入事件的响应方法。
     * @param e 事件相关信息
     */
    public void OnMouseEnter(BaseEventData e) {
        // 取消调用隐藏自身方法
        CancelInvoke("Hide");

        // 显示
        mPanel.SetActive(true);
    }

    /**
     * 鼠标离开事件的响应方法。
     * @param e 事件相关信息
     */
    public void OnMouseExit(BaseEventData e) {
        // 延迟调用隐藏自身方法
        Invoke("Hide", 0.5f);
    }

    /**
     * 设置菜单项标题。
     * @param position  位置
     * @param title     标题
     */
    public void SetMenuItemTitle(int position, string title) {
        mMenuItems[position].GetComponentInChildren<Text>().text = title;
    }
}
